package pt.compflow.interfaces.task;

import java.util.HashSet;
import java.util.Set;

import pt.compflow.Context;
import pt.compflow.flowontology.model.Assignment;
import pt.compflow.flowontology.model.FLOWO;
import pt.compflow.flowontology.model.FlowOntologyModel;
import pt.compflow.flowontology.model.Task;
import pt.compflow.flowontology.model.Worker;
import pt.compflow.graph.Tree;
import pt.compflow.interfaces.IOInterfaceBase;
import pt.compflow.interfaces.InterfaceListener;
import pt.compflow.storage.TripleStoreConnection;
import pt.compflow.tools.OntModelHelper;

import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.vocabulary.RDF;

public abstract class TaskInterfaceBase extends IOInterfaceBase implements TaskInterface {

	public TaskInterfaceBase() {
	}

	public TaskInterfaceBase(TaskInterfaceBase interfaze) {
		super(interfaze);
	}
	
	@Override
	public void request(Context context, TripleStoreConnection store, OntModelHelper ontModelHelper, FlowOntologyModel jobModel, FlowOntologyModel engineModel, String jobUri, Task task) {
		// setup workers
		boolean ok = false;
		
		Resource taskClass = ontModelHelper.getDirectLeafType(task, FLOWO.Task.getURI());
				
		Tree performedByTree = ontModelHelper.getApplicableEdgeDestinationsClosure(FLOWO.performedBy.getURI(), taskClass.getURI(), FLOWO.Activity.getURI());
		Set<String> doneSet = new HashSet<String>();
		
		if(performedByTree != null && !performedByTree.isEmpty()) {
			boolean isHasValue = false;
			for(Tree performedByValue : performedByTree) {
			
				if(ontModelHelper.getOntModel().getResource(performedByValue.getNode()).canAs(OntClass.class)) {
					if(!isHasValue) {
						// get instances of the classes 
						StmtIterator stmtIt = engineModel.listStatements(null, RDF.type, engineModel.getResource(performedByValue.getNode()));
						while(stmtIt.hasNext()) {
							Worker worker = stmtIt.next().getSubject().as(Worker.class);
							if(!doneSet.contains(worker.getURI()) && worker.hasProperty(FLOWO.accessibleThrough, engineModel.getTaskInterfaceWithURI(interfaceUri))) {
								ok = true;
								doneSet.add(worker.getURI());
								request(context, store, ontModelHelper, jobModel, engineModel, jobUri, task, worker);
							}
						}
					}
				} else {
					Worker worker = engineModel.getWorkerWithURI(performedByValue.getNode());
					if(worker != null && !doneSet.contains(worker.getURI()) && worker.hasProperty(FLOWO.accessibleThrough, engineModel.getTaskInterfaceWithURI(interfaceUri))) {
						ok = true;
						doneSet.add(worker.getURI());
						request(context, store, ontModelHelper, jobModel, engineModel, jobUri, task, worker);
					}
				}
			}
		}
			
		if(!ok) {
			throw new RuntimeException("No workers to request " + task.getURI() + " were found in the engine environment!");
		}
	}
	
	protected abstract void request(Context context, TripleStoreConnection store, OntModelHelper ontModelHelper, FlowOntologyModel jobModel, FlowOntologyModel engineModel, String jobUri, Task task, Worker worker);

	@Override
	public boolean onTaskAccepted(String jobUri, Worker worker, Task task) {
		boolean res = false;
		for (InterfaceListener listener : listeners)
			if(((TaskInterfaceListener) listener).onTaskAccepted(jobUri, task.getURI(), worker.getURI(), interfaceUri))
				res = true;
		
		return res;
	}

	@Override
	public boolean onAssignmentSolved(String jobUri, Worker worker, Task task, Assignment assignment) {
		boolean res = false;
		for (InterfaceListener listener : listeners)
			if(((TaskInterfaceListener) listener).onAssignmentSolved(jobUri, task.getURI(), assignment.getURI(), worker.getURI(), interfaceUri))
				res = true;
		
		return res;
	}

}
